package de.mrapp.tabswitcher.example.slice;

import de.mrapp.tabswitcher.*;
import de.mrapp.tabswitcher.colorUi.util.ColorUiUtil;
import de.mrapp.tabswitcher.example.ResourceTable;
import de.mrapp.tabswitcher.example.SettingsAbility;
import de.mrapp.tabswitcher.example.adapter.CustomArrayAdapter;
import de.mrapp.tabswitcher.example.adapter.DataBinder;
import de.mrapp.tabswitcher.example.base.BaseAbilitySlice;
import de.mrapp.tabswitcher.menu.OnMenuItemClickListener;
import de.mrapp.tabswitcher.snackbar.SnackBar;
import de.mrapp.tabswitcher.util.DimensionUtil;
import de.mrapp.tabswitcher.util.LogUtil;
import de.mrapp.tabswitcher.util.PixelUtil;
import de.mrapp.tabswitcher.view.Toolbar;
import de.mrapp.util.Condition;
import de.mrapp.ohos_util.multithreading.AbstractDataBinder;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.*;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.global.resource.solidxml.Theme;
import ohos.utils.PacMap;
import ohos.utils.Sequenceable;

import java.util.Arrays;

public class MainAbilitySlice extends BaseAbilitySlice implements TabSwitcherListener {

    private boolean darkTheme;
    // 主要用于清除所有Tab时，需要延时执行，使动画能顺利执行完
    private long startClearAllMills;
    private EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());

    private class State extends AbstractState implements AbstractDataBinder.Listener<CustomArrayAdapter<String>, Tab, ListContainer, Void>, TabPreviewListener {

        private CustomArrayAdapter<String> adapter;

        State(final Tab tab) {
            super(tab);
        }

        public void loadItems(final ListContainer listView) {
            Condition.INSTANCE.ensureNotNull(listView, "The list view may not be null");

            if (adapter == null) {
                dataBinder.addListener(this);
                dataBinder.load(getTab(), listView);
            } else if (listView.getItemProvider() != adapter) {
                listView.setItemProvider(adapter);
            }
        }

        @Override
        public boolean onLoadData(AbstractDataBinder<CustomArrayAdapter<String>, Tab, ListContainer, Void> dataBinder, Tab key, Void... params) {
            return true;
        }

        @Override
        public void onCanceled(AbstractDataBinder<CustomArrayAdapter<String>, Tab, ListContainer, Void> dataBinder) {

        }

        @Override
        public void onFinished(AbstractDataBinder<CustomArrayAdapter<String>, Tab, ListContainer, Void> dataBinder, Tab key, CustomArrayAdapter<String> data, ListContainer view, Void... params) {
            if (getTab().equals(key)) {
                view.setItemProvider(data);
                adapter = data;
                dataBinder.removeListener(this);
            }
        }

        @Override
        public void saveInstanceState(PacMap outState) {
            if (adapter != null && !adapter.isEmpty()) {
                String[] array = new String[adapter.getCount()];

                for (int i = 0; i < array.length; i++) {
                    array[i] = adapter.getItem(i);
                }
                outState.putStringArray(String.format(ADAPTER_STATE_EXTRA, getTab().getTitle()), array);
            }
        }

        @Override
        public void restoreInstanceState(PacMap savedInstanceState) {
            if (savedInstanceState != null) {
                String key = String.format(ADAPTER_STATE_EXTRA, getTab().getTitle());
                String[] items = savedInstanceState.getStringArray(key);

                if (items != null && items.length > 0) {
                    adapter = new CustomArrayAdapter<>(getContext(), ResourceTable.Layout_simple_list_item_1,  Arrays.asList(items));
                }
            }
        }

        @Override
        public boolean onLoadTabPreview(TabSwitcher tabSwitcher, Tab tab) {
            return !getTab().equals(tab) || adapter != null;
        }
    }

    private String getThemeValue(String name) {
        Theme theme = getContext().getTheme();
        String theme_name = "";
        try {
            theme_name = theme.getStringValue(name);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return theme_name;
    }

    private class Decorator extends StatefulTabSwitcherDecorator<State> {

        @Override
        protected State onCreateState(Context context, TabSwitcher tabSwitcher, Component view, Tab tab, int index, int viewType, PacMap savedInstanceState) {
            if (viewType == 2) {
                State state = new State(tab);
                tabSwitcher.addTabPreviewListener(state);

                if (savedInstanceState != null) {
                    state.restoreInstanceState(savedInstanceState);
                }

                return state;
            }
            return null;
        }

        @Override
        protected void onClearState(State state) {
            tabSwitcher.removeTabPreviewListener(state);
        }

        @Override
        protected void onSaveInstanceState(Component view, Tab tab, int index, int viewType, State state, PacMap outState) {
            if (state != null) {
                state.saveInstanceState(outState);
            }
        }

        @Override
        public Component onInflateView(LayoutScatter inflater, ComponentContainer parent, int viewType) {
            Component view;
            if (viewType == 0) {
                LogUtil.loge("=== onInflateView 0");
                view = inflater.parse(ResourceTable.Layout_tab_text_view, parent, false);
            } else if (viewType == 1) {
                LogUtil.loge("=== onInflateView 1");
                view = inflater.parse(ResourceTable.Layout_tab_edit_text, parent, false);
            } else {
                LogUtil.loge("=== onInflateView 2");
                view = inflater.parse(ResourceTable.Layout_tab_list_view, parent, false);
            }

            Toolbar toolbar = (Toolbar) view.findComponentById(ResourceTable.Id_toolbar);
            toolbar.inflateMenu(ResourceTable.Layout_tab);
            toolbar.setOnMenuItemClickListener(tabSwitcher, createToolbarMenuListener());
            TabSwitcher.setupWithToolbar(tabSwitcher, toolbar, createTabSwitcherButtonListener());
            return view;
        }

        @Override
        protected void onShowTab(Context context, TabSwitcher tabSwitcher, Component view, Tab tab, int index, int viewType, State state, PacMap savedInstanceState) {

            Text textView = findComponentById(ResourceTable.Id_title);
            textView.setText((String) tab.getTitle());
            Toolbar toolbar = findComponentById(ResourceTable.Id_toolbar);
            toolbar.addMenuClickListener();
            toolbar.setVisibility(tabSwitcher.isSwitcherShown() ? Component.HIDE : Component.VISIBLE);
            if (toolbar.getMenu() != null) {
                String theme_name = getThemeValue("theme_name");
                if ("dark".equals(theme_name)) {
                    toolbar.getMenu().setImageSrc(de.mrapp.tabswitcher.ResourceTable.Media_more_menu_white);
                    toolbar.setButtonColor(1, Color.WHITE);
                } else {
                    toolbar.getMenu().setImageSrc(de.mrapp.tabswitcher.ResourceTable.Media_more_menu);
                    toolbar.setButtonColor(0.5f, Color.DKGRAY);
                }
            }
            ColorUiUtil.changeTheme(view, getContext().getTheme());
            if (viewType == 1) {
                LogUtil.loge("=== onShowTab viewType -> 1");
                TextField editText = findComponentById(ResourceTable.Id_edit);

                if (savedInstanceState == null) {
                    editText.setText("");
                }

                editText.requestFocus();
            } else if (viewType == 2 && state != null) {
                LogUtil.loge("=== onShowTab viewType -> 2");
                ListContainer listView = findComponentById(ResourceTable.Id_list);
                state.loadItems(listView);
            }
        }


        @Override
        public int getViewTypeCount() {
            return 3;
        }


        @Override
        public int getViewType(Tab tab, int index) {
            LogUtil.loge("=== getViewType index: " + index);
            PacMap parameters = tab.getParameters();
            return parameters != null ? parameters.getIntValue(VIEW_TYPE_EXTRA) : 0;
        }

    }

    /**
     * The name of the extra, which is used to store the view type of a tab within a bundle.
     */
    private static final String VIEW_TYPE_EXTRA = MainAbilitySlice.class.getName() + "::ViewType";

    /**
     * The name of the extra, which is used to store the state of a list adapter within a bundle.
     */
    private static final String ADAPTER_STATE_EXTRA = State.class.getName() + "::%s::AdapterState";

    /**
     * The number of tabs, which are contained by the example app's tab switcher.
     */
    private static final int TAB_COUNT = 12;

    /**
     * The ability's tab switcher.
     */
    private TabSwitcher tabSwitcher;
    private DirectionalLayout main_root;

    /**
     * The decorator of the ability's tab switcher.
     */
    private Decorator decorator;

    /**
     * The ability's snackbar.
     */
    private SnackBar snackbar;

    /**
     * The data binder, which is used to load the list items of tabs.
     */
    private DataBinder dataBinder;

    @Override
    protected int getLayoutId() {
        return ResourceTable.Layout_ability_main;
    }

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        darkTheme = "dark".equals(getThemeValue("theme_name"));
        dataBinder = new DataBinder(this, darkTheme);
        decorator = new Decorator();
        main_root = (DirectionalLayout) findComponentById(ResourceTable.Id_root);
        tabSwitcher = (TabSwitcher) findComponentById(ResourceTable.Id_tab_switcher);
        tabSwitcher.clearSavedStatesWhenRemovingTabs(false);
        tabSwitcher.getComponentTreeObserver().addWindowBoundListener(createWindowInsetsListener());
        tabSwitcher.setDecorator(decorator);
        tabSwitcher.addListener(this);
        tabSwitcher.showToolbars(true);

        for (int i = 0; i < TAB_COUNT; i++) {
            tabSwitcher.addTab(createTab(i));
        }

        tabSwitcher.showAddTabButton(createAddTabButtonListener());
        tabSwitcher.setToolbarNavigationIcon(ResourceTable.Media_ic_plus_white_24dp, createAddTabListener());
        TabSwitcher.setupWithToolbar(tabSwitcher, createTabSwitcherButtonListener());
        inflateMenu();
    }

    private Component.ClickedListener createAddTabListener() {
        return new Component.ClickedListener() {

            @Override
            public void onClick(final Component view) {
                LogUtil.loge("=== createAddTabListener");
                int index = tabSwitcher.getCount();
                Animation animation = createRevealAnimation();
                tabSwitcher.addTab(createTab(index), 0, animation);
            }

        };
    }

    private ComponentTreeObserver.WindowBoundListener createWindowInsetsListener() {
        return new ComponentTreeObserver.WindowBoundListener() {
            @Override
            public void onWindowBound() {
                int left = main_root.getLeft();
                int top = main_root.getTop();
                int right = main_root.getRight();
                int bottom = main_root.getBottom();
                float touchableAreaTop = top;

                if (tabSwitcher.getLayout() == Layout.TABLET) {
//                    touchableAreaTop += getResources().getDimensionPixelSize(R.dimen.tablet_tab_container_height);
                }

                LogUtil.loge("===" + left + ":" + top + ":" + right + ":" + bottom);
                int actionBarSize = (int) PixelUtil.fp2px(DimensionUtil.parseDimension(tabSwitcher.getContext().getString(ResourceTable.String_actionBarSize)));
                LogUtil.loge("===" + actionBarSize);
                RectFloat touchableArea = new RectFloat(left, touchableAreaTop, right, (float) ((double)touchableAreaTop + (double)actionBarSize));
                tabSwitcher.addDragGesture(
                        new SwipeGesture.Builder().setTouchableArea(touchableArea).create());
                tabSwitcher.addDragGesture(
                        new PullDownGesture.Builder().setTouchableArea(touchableArea).create());
            }

            @Override
            public void onWindowUnbound() {

            }
        };
    }

    private Component.ClickedListener createTabSwitcherButtonListener() {
        return new Component.ClickedListener() {

            @Override
            public void onClick(final Component view) {
                LogUtil.loge("=== createTabSwitcherButtonListener");
                tabSwitcher.toggleSwitcherVisibility();
            }

        };
    }

    private AddTabButtonListener createAddTabButtonListener() {
        return new AddTabButtonListener() {

            @Override
            public void onAddTab(final TabSwitcher tabSwitcher) {
                int index = tabSwitcher.getCount();
                Tab tab = createTab(index);
                tabSwitcher.addTab(tab, 0);
            }

        };
    }

    private Animation createRevealAnimation() {
        float x = 0;
        float y = 0;
        Component view = getNavigationMenuItem();

        if (view != null) {
            int[] location = view.getLocationOnScreen();
            x = (float) ((double)location[0] + (view.getWidth() / 2d));
            y = (float) ((double)location[1] + (view.getHeight() / 2d));
        }

        return new RevealAnimation.Builder().setX(x).setY(y).create();
    }

    private Animation createPeekAnimation() {
        return new PeekAnimation.Builder().setX(tabSwitcher.getWidth() / 2f).create();
    }

    private Component getNavigationMenuItem() {
        Toolbar[] toolbars = tabSwitcher.getToolbars();

        if (toolbars != null) {
            Toolbar toolbar = toolbars.length > 1 ? toolbars[1] : toolbars[0];
            int size = toolbar.getChildCount();

            for (int i = 0; i < size; i++) {
                Component child = toolbar.getComponentAt(i);
                if (child instanceof Image) {
                    return child;
                }
            }
        }
        return null;
    }

    private void inflateMenu() {
        tabSwitcher.inflateToolbarMenu(tabSwitcher.getCount() > 0 ? ResourceTable.Layout_tab_switcher : ResourceTable.Layout_tab, createToolbarMenuListener());
    }

    private Tab createTab(final int index) {
        String title = getString(ResourceTable.String_tab_title, index + 1);
        Tab tab = new Tab(title);
        PacMap parameters = new PacMap();
        parameters.putIntValue(VIEW_TYPE_EXTRA, index % 3);
        tab.setParameters(parameters);
        return tab;
    }

    private OnMenuItemClickListener createToolbarMenuListener() {
        return new OnMenuItemClickListener() {


            @Override
            public boolean onMenuItemClick(final Component item) {
                switch (item.getId()) {
                    case ResourceTable.Id_remove_tab_menu_item:
                        Tab selectedTab = tabSwitcher.getSelectedTab();

                        if (selectedTab != null) {
                            tabSwitcher.removeTab(selectedTab);
                        }

                        return true;
                    case ResourceTable.Id_add_tab_menu_item:
                        int index = tabSwitcher.getCount();
                        Tab tab = createTab(index);

                        if (tabSwitcher.isSwitcherShown()) {
                            tabSwitcher.addTab(tab, 0, createRevealAnimation());
                        } else {
                            tabSwitcher.addTab(tab, 0, createPeekAnimation());
                        }

                        return true;
                    case ResourceTable.Id_clear_tabs_menu_item:
                        startClearAllMills = System.currentTimeMillis();
                        tabSwitcher.clear();
                        return true;
                    case ResourceTable.Id_settings_menu_item:
                        Operation operation = new Intent.OperationBuilder()
                                .withDeviceId("")
                                .withBundleName(BuildConfig.PACKAGE_NAME + ".example")
                                .withAbilityName(SettingsAbility.class)
                                .build();
                        Intent i = new Intent();
                        i.setOperation(operation);
                        startAbility(i);
                        return true;
                    default:
                        return false;
                }
            }
        };
    }

    private void showUndoSnackbar(final String text, final int index, boolean clearAll, final Tab... tabs) {
        SnackBar.Builder builder = new SnackBar.Builder(getAbility(), main_root);
        builder.withOnClickListener(createUndoSnackbarListener(index, clearAll, tabs))    // 弹框按钮点击效果
                .withMessage(text)                                                        // 弹框文本信息
                .withActionMessage(getStringValue(ResourceTable.String_undo))            // 弹框按钮文本信息
                .withStyle(Color.getIntColor("#20c7c6"))                        // 弹框文本信息颜色设置
                .withBackgroundColorId(Color.getIntColor("#313131"))                            // 弹框按钮颜色设置
                .withTypeFace(Font.DEFAULT)
                .withClearQueued()
                .withDuration(SnackBar.LONG_SNACK);                                        // 弹框持续时间设置
        snackbar = builder.show();
    }

    private String getStringValue(int resId) {
        String undo = "";
        try {
            undo = getResourceManager().getElement(resId).getString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return undo;
    }

    private SnackBar.OnMessageClickListener createUndoSnackbarListener(final int index, final boolean clearAll, final Tab... tabs) {
        return new SnackBar.OnMessageClickListener() {

            @Override
            public void onMessageClick(Sequenceable sequenceable) {
                if (snackbar == null) {
                    return;
                }
                snackbar.hide();
                if (tabSwitcher.isSwitcherShown()) {
                    long undoAllTimeMills = System.currentTimeMillis();
                    LogUtil.loge("=== time" + (undoAllTimeMills - startClearAllMills));
                    if(clearAll && (undoAllTimeMills - startClearAllMills) < 800) {
                        handler.postTask(()-> {
                            tabSwitcher.addAllTabs(tabs, index);
                        } , 800 - ((undoAllTimeMills - startClearAllMills)));
                        return;
                    }
                    tabSwitcher.addAllTabs(tabs, index);
                } else if (tabs.length == 1) {
                    tabSwitcher.addTab(tabs[0], 0, createPeekAnimation());
                }
            }

        };
    }


    @Override
    public void onSwitcherShown(TabSwitcher tabSwitcher) {
        LogUtil.loge("=== onSwitcherShown");
    }

    @Override
    public void onSwitcherHidden(TabSwitcher tabSwitcher) {
        LogUtil.loge("=== onSwitcherHidden");
        if (snackbar != null) {
            snackbar.hide();
        }
    }

    @Override
    public void onSelectionChanged(TabSwitcher tabSwitcher, int selectedTabIndex, Tab selectedTab) {

    }

    @Override
    public void onTabAdded(TabSwitcher tabSwitcher, int index, Tab tab, Animation animation) {
        inflateMenu();
        TabSwitcher.setupWithToolbar(tabSwitcher, createTabSwitcherButtonListener());
    }

    @Override
    public void onTabRemoved(TabSwitcher tabSwitcher, int index, Tab tab, Animation animation) {
        String text = getString(ResourceTable.String_removed_tab_snackbar, tab.getTitle());
        showUndoSnackbar(text, index, false, tab);
        inflateMenu();
        TabSwitcher.setupWithToolbar(tabSwitcher, createTabSwitcherButtonListener());
    }

    @Override
    public void onAllTabsRemoved(TabSwitcher tabSwitcher, Tab[] tabs, Animation animation) {
        String text = getString(ResourceTable.String_cleared_tabs_snackbar);
        showUndoSnackbar(text, 0,true, tabs);
        inflateMenu();
        TabSwitcher.setupWithToolbar(tabSwitcher, createTabSwitcherButtonListener());
    }
}
